/**
 * 2017年6月1日
 */
package cn.edu.bjtu.entity.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.edu.bjtu.entity.ExecuteContextResult;

/**
 * 如果并发控制不在这个项目中控制,那就直接继承自这个类.
 * 使用HTTPCLIENT用于访问HTTP接口.
 * 未测试过.
 * @author Alex
 *
 */
public abstract class BaseHttpContextWithoutLock<R> implements ExecuteContextResult<R>{
		protected R result;
		public static final String METHOD_GET = "get";
		public static final String METHOD_POST = "post";
		protected static final ObjectMapper om = new ObjectMapper();
		boolean executing = false;
		boolean async = false;
		boolean failed = false;
		protected String msg = null;
		private HttpClientBuilder dhb = HttpClientBuilder.create();//.setDefaultSocketConfig(sc);
	
		public BaseHttpContextWithoutLock() {
			om.enableDefaultTyping();
			
		}
		public String getMethod(){
			return METHOD_GET;
		}
		public abstract URI getURI();
		public abstract String getHostname();
		/**
		 * 子类重写这个方法不要在里面处理异常,直接将异常抛出,这样页面才可以正常显示错误提示.
		 * 如果要自己处理异常请设置正确的提示信息.
		 * @param in
		 * @param entity
		 * @throws Exception
		 */
		protected abstract void handleResponseInputStream(InputStream in,HttpEntity entity) throws Exception;
		public  HttpEntity getPostEntity(){
			return null;
		}
		public int getPort(){
			return 8080;
		}
		public HttpClient getClient(){
			return dhb.build();
		}
		public void fire(){
			this.executing = true;
			this.failed = false;
			HttpClient hc = getClient();
			HttpRequest hr = null;
			HttpHost hh =  new HttpHost(getHostname(), getPort());
			HttpResponse response = null;
			switch(getMethod()){
			case METHOD_GET:
				hr = new HttpGet(getURI());
				break;
			case METHOD_POST:
				hr = new HttpPost(getURI());
				((HttpPost)hr).setEntity(getPostEntity());
				break;
			default:
				hr = new HttpGet(getURI());
			}
			try {
			    System.out.println("访问的URL"+getHostname()+" "+getURI().toString());
				response = hc.execute(hh,hr);
				HttpEntity entity = response.getEntity();
				InputStream in = entity.getContent();
				//所有重写这个方法的子类都不要自己处理异常了，直接抛出，让这里的 CATCH 来完成处理，并设置相应的标志位。
				handleResponseInputStream(in,entity);
				this.failed = false;
			} catch (Exception  e) {
				e.printStackTrace();
				this.failed = true;
				msg = e.getMessage();
			}finally{
				this.executing = false;
			}
		}
		@Override
		public boolean isNoCache() {
			return true;
		}

		@Override
		public String getInputDir() {
			return null;
		}

		@Override
		public String getOutPutDir() {
			return null;
		}

		@Override
		public boolean isAsync() {
			return async;
		}
		
		@Override
		public boolean isExist() {
			return true;
		}

		@Override
		public boolean isSuccess() {
			return !failed;
		}

		@Override
		public boolean isFailed() {
			return failed;
		}

		@Override
		public String getTipMessage() {
			return msg;
		}
		
		@Override
		public boolean isExecuting() {
			return executing;
		}
		/**
		 * 几乎所有的子类都需要这个 方法,所以把这个方法写到父类中,
		 * 并且添加了一个字段
		 * protected R result;
		 */
		@Override
		public R javaClassResult() {
			return result;
		}
		/**
		 * 打印返回的内容,用于debug
		 * @param in
		 * @throws IOException
		 */
		protected void printStream( InputStream in) throws IOException{
			BufferedReader br  = new BufferedReader(new InputStreamReader(in, "utf-8"));
			String line = "";
			while((line=br.readLine())!=null){
				System.out.println(line);
			}
		}

}
